﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using WebApplication1.Models;
using WebApplication1.Models.Database;
using WebApplication1.service;

namespace WebApplication1.Controllers
{
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class RedisController : ControllerBase
    {
        private readonly IDatabase _redis;
        private readonly WebEnterpriseIIContext _db;
        private readonly IRedisService _redisService;
        public RedisController(RedisHelper client, WebEnterpriseIIContext db, IRedisService redisService)
        {
            _db = db;
            //创建Redis连接对象
            _redis = client.GetDatabase();
            _redisService = redisService;
        }

        [HttpGet]
        public void SetRedisCache()
        {
            _redis.StringSet("RedisCache", "6666");
        }

        [HttpGet]
        public void RedisString()
        {
            var str = "广东工程职业技术学院";
            //写入String的值
            _redis.StringSet("StringCache", str);

            //获取String缓存的值
            var value = _redis.StringGet("StringCache");

            //追加字符
            _redis.StringAppend("StringCache", "666");

            //写入数据 5小时5分钟5秒 后过期
            _redis.StringSet("StringCache1", 1, new TimeSpan(5, 5, 5));

            //key为StringCache1的值自增1
            _redis.StringIncrement("StringCache1");

            //key为StringCache1的值增加10
            _redis.StringIncrement("StringCache1", 10);

            //key为StringCache1的值自减1
            _redis.StringDecrement("StringCache1");

            //key为StringCache1的值减少5
            _redis.StringDecrement("StringCache1", 5);
        }

        [HttpGet]
        public void StringText()
        {
            //写入goodName的值
            _redis.StringSet("goodName","华为手机");

            //获取goodName缓存的值
             _redis.StringGet("goodName");

            //写入数据 5小时5分钟5秒 后过期
            _redis.StringSet("goodName", "小米手机手机", new TimeSpan(0, 0, 20));

            //追加字符
            _redis.StringAppend("goodName", "666");

            //查看key为goodName的值长度
            _redis.StringLength("goodName");

        }

        [HttpGet]
        public void RedisHash()
        {
            var hashKey = "hashkeyTest";
            //hash写入单个数据
            _redis.HashSet(hashKey, "name", "刘备");

            //hash写入多个数据
            var hashEntrys = new HashEntry[] { new HashEntry("num", "1406200115"), new HashEntry("class", "软件A班"), new HashEntry("age", 18) };
            _redis.HashSet(hashKey, hashEntrys);

            //hash获取数据
            var value1 = _redis.HashGet(hashKey, "name");

            //hash获取所有数据
            var value2 = _redis.HashGetAll(hashKey);

            //判断hash的属性是否存在
            var value3 = _redis.HashExists(hashKey, "name");

            //hash的属性值自增，自减
            var value4 = _redis.HashIncrement(hashKey, "age");
            value4 = _redis.HashDecrement(hashKey, "age");

            //hash删除某个属性
            _redis.HashDelete(hashKey, "class");
        }

        [HttpGet]
        public void HashText()
        {
            //hash写入多个数据
            var values = new HashEntry[] { new HashEntry("name", "刘备"), new HashEntry("class", "软件技术B班"), new HashEntry("school", "广东工程职业技术学院"), new HashEntry("age", "1862"), new HashEntry("num", "1406200228") };
            _redis.HashSet("liubeiinfo", values);

            //hash获取所有数据
            _redis.HashGetAll("liubeiinfo");

            //hash修改学号
            _redis.HashSet("liubeiinfo", "num", "1406200230");

            //hash获取修改后的数据
            _redis.HashGet("liubeiinfo", "num");
        }


        [HttpGet]
        public void RedisList()
        {
            var listkey = "testlistkey1";
            //左侧推入单个元素  4 3 2 1
            _redis.ListLeftPush(listkey, "刘备");
            //左侧推入多个元素
            var redisValues1 = new RedisValue[] { "张飞", "关羽" };
            _redis.ListLeftPush(listkey, redisValues1);
            //右侧同理   1 2 3 4
            _redis.ListRightPush(listkey, "马超");
            var redisValues2 = new RedisValue[] { "赵云", "马岱" };
            _redis.ListRightPush(listkey, redisValues2);

            //获取所有元素
            _redis.ListRange(listkey, 0, -1);

            //获取指定索引的元素
            _redis.ListGetByIndex(listkey, 2);

            //从左边取出并一个并删除元素
            _redis.ListLeftPop(listkey);
            //从右边取出并一个并删除元素
            _redis.ListRightPop(listkey);
        }

        [HttpGet]
        public void ListText()
        {
            //左侧推入多个元素
            var redisValues1 = new RedisValue[] { "刘备", "关羽","张飞", "赵云", "马超", "曹操", "吕布" };
            _redis.ListLeftPush("userList", redisValues1);

            //获取所有元素
            _redis.ListRange("userList", 0, -1);

            // 在赵云和马超中间加入"黄盖" 栈 先进后出
            _redis.ListInsertAfter("userList", "马超", "黄盖");

            //获取修改后的元素
            _redis.ListRange("userList", 0, -1);
        }

        [HttpGet]
        public void RedisSet()
        {
            var setkey = "testsetkey1";
            //添加单个元素
            _redis.SetAdd(setkey, "刘备");
            //添加多个元素
            var redisValues1 = new RedisValue[] { "张飞", "关羽", "周瑜" };
            _redis.SetAdd(setkey, redisValues1);
            //移除某个元素
            _redis.SetRemove(setkey, "刘备");

            //获取所有成员
            var value1 = _redis.SetMembers(setkey);
            //随机获取一个元素
            var value2 = _redis.SetRandomMember(setkey);
            //随机获取多个元素
            var value3 = _redis.SetRandomMembers(setkey, 2);
            //判断是否包含某个元素
            _redis.SetContains(setkey, "马超");

            var setkey2 = "testsetkey2";
            var redisValues2 = new RedisValue[] { "张飞", "关羽", "马超", "赵云", "曹操", "黄盖" };
            _redis.SetAdd(setkey2, redisValues2);
            //获取两个集合的差集
            var value4 = _redis.SetCombine(SetOperation.Difference, setkey, setkey2);
            //获取两个集合的交集
            var value5 = _redis.SetCombine(SetOperation.Intersect, setkey, setkey2);
            //获取两个集合的并集
            var value6 = _redis.SetCombine(SetOperation.Union, setkey, setkey2);
        }


        [HttpGet]
        public void SetText()
        {
            //添加刘备同学关注的用户Id列表
            var redisValues1 = new RedisValue[] { 1214, 5651, 5654,2668,9595,9955 };
            _redis.SetAdd("followList_liu", redisValues1);

            //添加张飞同学关注的用户Id列表
            var redisValues2 = new RedisValue[] { 5985, 5651, 5654, 6555, 9595, 9998 };
            _redis.SetAdd("followList_zhang", redisValues2);

            //获取两个集合的交集
            _redis.SetCombine(SetOperation.Intersect, "followList_liu", "followList_zhang");
        }

        [HttpGet]
        public void RedisZSet()
        {
            var zsetkey = "testzsetkey1";
            //添加单个元素
            _redis.SortedSetAdd(zsetkey, "刘备", 50);
            //添加多个元素
            var values = new[]
                { new SortedSetEntry("马超", 23), new SortedSetEntry("赵云", 50), new SortedSetEntry("关羽", 56) };
            _redis.SortedSetAdd(zsetkey, values);
            //移除某个元素
            _redis.SortedSetRemove(zsetkey, "马超");

            //给某个元素添加指定分数
            _redis.SortedSetIncrement(zsetkey, "马超", 1);
            //给某个元素减少指定分数
            _redis.SortedSetDecrement(zsetkey, "马超", 1);

            //获取某个分数段的元素
            var value1 = _redis.SortedSetRangeByScore(zsetkey, 50, 60);
            //获取某个分数段的元素及分数
            var value2 = _redis.SortedSetRangeByScoreWithScores(zsetkey, 50, 60);
            //获取某个排名段的元素
            var value3 = _redis.SortedSetRangeByRank(zsetkey, 0, 2);
            //获取某个排名段的元素及分数
            var value4 = _redis.SortedSetRangeByRankWithScores(zsetkey, 0, 2);
        }

        [HttpGet]
        public void ZSetText()
        {
            //添加多个元素
            var values = new[]
                { new SortedSetEntry("刘备", 90), new SortedSetEntry("张飞", 44), new SortedSetEntry("关羽", 55), new SortedSetEntry("赵云", 98),new SortedSetEntry("马超", 41),new SortedSetEntry("曹操", 91),new SortedSetEntry("吕布", 55),new SortedSetEntry("周瑜", 55) };
            _redis.SortedSetAdd("scorelist", values);

            // 获取某个排名段的元素
            var valuel=_redis.SortedSetRangeByRank("scorelist", 1, 4,Order.Descending);

            //获取某个分数段的元素
            var value2 = _redis.SortedSetRangeByScore("scorelist", 60, 100);
        }


            /// <summary>
            /// 
            /// </summary>
            [HttpGet]
        public void SerializeJSON()
        {
            //查询商品
            var good = _db.Goods.FirstOrDefault(x => x.Id == 10);
            //转化为json字符串
            var jsonStr = JsonConvert.SerializeObject(good);
            //json字符串保存到redis
            _redis.StringSet("goodinfo", jsonStr);
            //从redis取出json字符串
            var redisStr = _redis.StringGet("goodinfo");
            //转化为对象 反序列化
            var jsonObj = JsonConvert.DeserializeObject<Good>(redisStr);
        }


        /// <summary>
        /// 获取商品列表
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public List<Good> GetGoodList()
        {
            //完成！！！ 使用本地缓存保存查询结果，缓存时间为30分钟
            //查询商品

            //获取redis的缓存，看有无数据
            var cache=_redis.StringGet("GoodCache");

            
            //1、先查看缓存有没有商品数据 key     变量类型和变量名
            if (cache.HasValue)
            {
                //转化为对象 反序列化
                var jsonObj = JsonConvert.DeserializeObject<List<Good>>(cache);
                //3、如果有则直接返回缓存数据
                return jsonObj;
            }
            else
            {
                //2、如果没有则去数据库查询并且把查询结果保存到缓存 缓存时间为30分钟
                var goods = _db.Goods.ToList();
                //转化为字符串 序列化
                var jsonStr = JsonConvert.SerializeObject(goods);
                //设置字符串缓存
                _redis.StringSet("GoodCache", jsonStr,new TimeSpan(0,30,0));
                return goods;
            }
        }

        /// <summary>
        /// 获取商品详情
        /// </summary>
        /// <param name="goodId"></param>
        /// <returns></returns>
        [HttpGet]
        [Authorize]
        public Good GetGoodInfo(int goodId)
        {
            //Redis5种数据类型ZSET  LIST
            //思考有无更好的方式去实现需求  更适合 更舒服的方法！！！
            //商品详情
            var good = _db.Goods.FirstOrDefault(x => x.Id == goodId);

            //使用本地缓存保存登录用户浏览商品记录(多个商品)
            var userId = Response.HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier).Value;
            //之前缓存下来的浏览记录  每个用户浏览记录都是单独的 每个用户都有自己的key  UserViews28\UserViews20

            //var record = cache.Get<List<Good>>($"UserViews{userId}");
            //等于
            var recordStr = _redis.StringGet($"UserViews{userId}");
            var record = JsonConvert.DeserializeObject<List<Good>>(recordStr);

            //浏览商品记录
            var views = new List<Good>();
            views.Add(good); //永远只有刚刚看的这一条商品数据

            //是不是还应该有前面的数据
            if (record != null)
                views.AddRange(record); //我前面看过的数据

            //cache.Set($"UserViews{userId}", views);
            //等于
            var jsonStr = JsonConvert.SerializeObject(views);
            _redis.StringSet($"UserViews{userId}", jsonStr);
            return good;
        }
        //Redis5种数据类型ZSET  LIST
        //思考有无更好的方式去实现需求  更适合 更舒服的方法！！！

        /// <summary>
        /// 获取商品详情 List 
        /// </summary>
        /// <param name="goodId"></param>
        /// <returns></returns>
        [HttpGet]
        [Authorize]
        public Good GetGoodInfo1(int goodId)
        {
            //商品详情
            var good = _db.Goods.FirstOrDefault(x => x.Id == goodId);

            // List 有序的列表 有序的商品数据 顺序：浏览的顺序 数据 商品数据
            // KEY
            //使用本地缓存保存登录用户浏览商品记录(多个商品)
            var userId = Response.HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier).Value;

            _redisService.AddGooodView(Convert.ToInt32(userId), good);
            //_redis.ListRange(key, 10, 14);
            return good;
        }

        /// <summary>
        /// 获取商品详情 ZSET 记录浏览时间
        /// </summary>
        /// <param name="goodId"></param>
        /// <returns></returns>
        [HttpGet]
        [Authorize]
        public Good GetGoodInfo2(int goodId)
        {
            //商品详情
            var good = _db.Goods.FirstOrDefault(x => x.Id == goodId);

            // List 有序的列表 有序的商品数据 顺序：浏览的顺序 数据 商品数据
            // KEY
            //使用本地缓存保存登录用户浏览商品记录(多个商品)
            var userId = Response.HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier).Value;
            //之前缓存下来的浏览记录  每个用户浏览记录都是单独的 每个用户都有自己的key  UserViews28\UserViews20
            var key = $"UserViews{userId}";

            //浏览记录 前面是最近浏览的 后面是
            //获取浏览记录的接口 前5的
            var jsonStr = JsonConvert.SerializeObject(good);
            //1681547627 转换成 2023年4月15 16 ：33：20
            //2023年4月15 16 ：34：20 转换成 时间戳 Int
            //商品 + 分数（浏览时间的时间戳） 
            var score = 0;//当前时间的时间戳
            _redis.SortedSetAdd(key, jsonStr, score);
            //以分数做排名 分数高的在前面 就能获取到最新的浏览商品列表 并且可以获取到每个商品的浏览时间
            return good;
        }

        //获取商品浏览记录 获取最新的浏览商品记录 上面是最新的
        [HttpGet]
        public void List()
        {
            //长度-获取数量 ， 长度 分页
            _redis.ListRange("", 0, 4);
        }

        //添加购物车
        [HttpGet]
        [Authorize] //授权
        public string AddCar(int goodId)
        {
            //使用本地缓存保存登录用户浏览商品记录(多个商品)
            var userId = Response.HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier).Value;
            //每个用户的Key
            var key = "car_" + userId;

            //添加一个购物车商品
            _redis.HashIncrement(key, goodId);

            return "添加成功";
        }

        //减少购物车
        [HttpGet]
        [Authorize] //授权
        public string DiffCar(int goodId)
        {
            //使用本地缓存保存登录用户浏览商品记录(多个商品)
            var userId = Response.HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier).Value;
            //每个用户的Key
            var key = "car_" + userId;

            //添加一个购物车商品 
            var count = _redis.HashDecrement(key, goodId);
            //减少之后如果是0 就删掉
            if (count == 0)
            {
                _redis.HashDelete(key, goodId);
            }
            return "减少成功";
        }

        //删除购物车
        [HttpGet]
        [Authorize] //授权
        public string DeleteCar(int goodId)
        {
            //使用本地缓存保存登录用户浏览商品记录(多个商品)
            var userId = Response.HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier).Value;
            //每个用户的Key
            var key = "car_" + userId;
            _redis.HashDelete(key, goodId);
            return "删除成功";
        }

        //查询购物车商品
        [HttpGet]
        [Authorize] //授权
        public List<GetCarModel> GetCar()
        {
            //使用本地缓存保存登录用户浏览商品记录(多个商品)
            var userId = Response.HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier).Value;
            //每个用户的Key
            var key = "car_" + userId;
            //查询hash所有数据
            var data = _redis.HashGetAll(key);
            var list = new List<GetCarModel>();
            //循环遍历hash所有数据 添加到模型
            foreach (var item in data)
            {
                //通过商品Id查询 商品详细信息
                var good = _db.Goods.FirstOrDefault(x => x.Id == (int)item.Name);
                if (good != null)
                {
                    list.Add(new GetCarModel()
                    {
                        GoodId = (int)item.Name,
                        Count = (int)item.Value,
                        Name = good.Name,
                        Price = good.Price,
                        Cover = good.Cover
                    });
                }
            }
            return list;
        }

             

        #region 关注模型

        /// <summary>
        /// 关注用户
        /// </summary>
        /// <param name="followUserId"></param>
        /// <returns></returns>
        [Authorize]
        [HttpGet]
        public string FollowUser(int followUserId)
        {
            var userId = Response.HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier).Value;
            var key = "follow_" + userId;
            //添加到集合
            _redis.SetAdd(key, followUserId);
            return "关注成功";
        }
        /// <summary>
        /// 取消关注
        /// </summary>
        /// <param name="followUserId"></param>
        /// <returns></returns>
        [Authorize]
        [HttpGet]
        public string UnFollowUser(int followUserId)
        {
            var userId = Response.HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier).Value;
            var key = "follow_" + userId;
            //从集合删除
            _redis.SetRemove(key, followUserId);
            return "取消关注成功";
        }

        /// <summary>
        /// 查看某个用户关注的人
        /// </summary>
        /// <returns></returns>
        [Authorize]
        [HttpGet]
        public List<int> FollowList(int userId)
        {
            var key = "follow_" + userId;
            var list = _redis.SetMembers(key);
            //转换成listint
            return list.Select(x => (int)x).ToList();
        }

        /// <summary>
        /// 获取两个用户同时关注的人
        /// </summary>
        [Authorize]
        [HttpGet]
        public List<int> IntersectUserList(int userId2)
        {
            var key = "follow_";
            //获取登录用户Id
            var userId = Response.HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier).Value;
            //求两个集合的交集
            var list = _redis.SetCombine(SetOperation.Intersect, key + userId, key + userId2);
            //转换成listint
            return list.Select(x => (int)x).ToList();
        }

        /// <summary>
        /// 获取两个用户关注的用户总和
        /// </summary>
        [Authorize]
        [HttpGet]
        public List<int> UnionUserList(int userId2)
        {
            var key = "follow_";
            //获取登录用户Id
            var userId = Response.HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier).Value;
            //求两个集合的交集
            var list = _redis.SetCombine(SetOperation.Union, key + userId, key + userId2);
            //转换成listint
            return list.Select(x => (int)x).ToList();
        }

        /// <summary>
        /// A相对于B可能认识的人
        /// </summary>
        [Authorize]
        [HttpGet]
        public List<int> DifferenceUserList(int userId2)
        {
            var key = "follow_";
            //获取登录用户Id
            var userId = Response.HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier).Value;
            //求两个集合的交集
            var list = _redis.SetCombine(SetOperation.Difference, key + userId, key + userId2);
            //转换成listint
            return list.Select(x => (int)x).ToList();
        }

        #endregion

    }
}
